package org.zjz.basket.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.zjz.basket.enums.JwtBodyKeyEnum;

import javax.crypto.SecretKey;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * Desc: JWT工具类
 *
 * @author gezq
 * @since 3/31/2022 - 3:25 PM
 */
@Component
@Slf4j
public final class JwtUtils {

    /**
     * 随机生成的安全密钥
     */
    private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    /**
     * 创建Jwt
     *
     * @param iss    签发者
     * @param sub    相关主题
     * @param aud    接收者
     * @param ttl    过期秒数
     * @param claims 自定义Claims
     * @return 生成的Jwt字符串
     */
    public String createJwt(String iss, String sub, String aud, long ttl, Map<String, Object> claims) {
        final Date expDate = DateTimeUtils.transLocalDateTimeToDate(LocalDateTime.now().plusSeconds(ttl));
        final Date nowDate = DateTimeUtils.transLocalDateTimeToDate(LocalDateTime.now());

        JwtBuilder jwtBuilder = Jwts.builder()
                .setIssuer(iss)
                .setSubject(sub)
                .setAudience(aud)
                .setExpiration(expDate)
                .setNotBefore(nowDate)
                .setIssuedAt(nowDate)
                .setId(String.valueOf(UUID.randomUUID()))
                .signWith(SECRET_KEY)
                .compressWith(CompressionCodecs.DEFLATE);
        claims.forEach(jwtBuilder::claim);
        String jwt = jwtBuilder.compact();
        log.info("create JWT: {}", jwt);
        return jwt;
    }

    /**
     * 解析Jwt
     *
     * @param jwt 待解析Jwt
     * @return Jwt主体部分
     */
    public Claims parseJwt(String jwt) {
        Claims res = null;
        try {
            res = Jwts.parserBuilder()
                    .setSigningKey(SECRET_KEY)
                    .build()
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (JwtException | IllegalArgumentException e) {
            log.error("parse JWT failed, please check: {}", e.getMessage());
        }
        assert res != null;
        return res;
    }

    /**
     * 获取指定name的内置value
     *
     * @param jwt  待解析jwt
     * @param key 指定key
     * @return value值
     */
    public String getBodyValue(String jwt, JwtBodyKeyEnum key) {
        Claims claims = parseJwt(jwt);
        switch (key) {
            case ISS: {
                return  claims.getIssuer();
            }
            case SUB: {
                return claims.getSubject();
            }
            case AUD: {
                return claims.getAudience();
            }
            default: {
                return "";
            }
        }
    }

    /**
     * 获取指定name的value
     *
     * @param jwt   待解析jwt
     * @param name  指定claim的名称
     * @param clazz 对应value的类型
     * @param <T>   指定类型
     * @return 指定类型的value
     */
    public <T> T getBodyValue(String jwt, String name, Class<T> clazz) {
        return parseJwt(jwt).get(name, clazz);
    }
}
